import React from 'react';
import { message } from 'antd';
import UploadItem from './item';
import { isReg } from './utils';
import styles from './styles.less';
import { PlusOutlined } from '@ant-design/icons';

type Props = {
  value?: string[] | string;
  maxSize: number;
  disabled?: boolean;
  regMessage?: string;
  maxUpload: number;
  regExp?: string | RegExp;
  onChange(value: string[] | string): any;
}

export type Upload = {
  url: string;
  key: string;
  file: File | null;
}

type State = {
  uploads: Upload[];
}

class UploadFile extends React.PureComponent<Props, State> {

  static defaultProps = {
    maxSize: 10,
    maxUpload: 1,
    disabled: false,
    onChange: () => null,
    regMessage: '上传文件类型不正确！',
  };

  state: State = {
    uploads: [],
  };

  componentDidMount() {
    const { value } = this.props;
    const urls = [].concat(value as any).filter(v => v);
    this.setState({
      uploads: urls.map((url: string, i:number) => {
        return { url, file: null, key: `key_${i}` };
      }),
    });
  }

  private inputFile = (
    React.createRef<HTMLInputElement>()
  );

  private checkSizePass = (file: File) => {
    const { maxSize } = this.props;
    const size = file.size / 1024 / 1024;
    return size > maxSize;
  };

  private getRegExp = (): RegExp => {
    const { regExp = '' } = this.props;
    return isReg(regExp) ? regExp : eval(regExp as string);
  };

  private checkFileType = (file: File) => {
    const { regExp } = this.props;
    if (!regExp) return true;
    return this.getRegExp().test(file.name);
  };

  private onFileChange = async ({ target }: any) => {
    const {
      maxSize,
      regMessage,
    } = this.props;
    const { files = [] } = target;
    const { uploads } = this.state;
    const file: File = files[0] || {};

    /* 检查文件类型 */
    if (!this.checkFileType(file)) {
      return message.error(regMessage);
    }

    /* 检查文件大小 */
    if (this.checkSizePass(file)) {
      return message.error(`上传文件不能大于${maxSize}M!`);
    }

    uploads.push({ file, url: '', key: `${Date.now()}` });
    this.setState({ uploads: [...uploads] });
  };

  private onTrigger = () => {
    this.onClear();
    this.inputFile.current?.click?.();
  };

  private onClear = () => {
    const input = this.inputFile.current as any;
    input.value = null;
  };

  private onUploadSuccess = (url: string, index: number) => {
    const { uploads } = this.state;
    const item = uploads[index];
    uploads[index] = { ...item, url };
    this.setState({ uploads: [...uploads] }, this.onChange);
  };

  private onDeleteItem = (index: number) => {
    const { uploads } = this.state;
    uploads.splice(index, 1);
    this.setState({ uploads: [...uploads] }, this.onChange);
  };

  private onChange = () => {
    const { uploads } = this.state;
    const urls = uploads.map((item: Upload) => item.url).filter(v => v);
    const value = urls.length <= 1 ? urls.join('') : urls;
    this.props?.onChange?.(value);
  };

  private renderTriggerButton = () => {
    const { uploads } = this.state;
    const { maxUpload } = this.props;
    if (uploads.length >= maxUpload) return null;
    const classList = [styles.trigger_button];
    if (maxUpload === 1) {
      classList.push(styles.upload_item_max);
    }
    return (
      <button
        type="button"
        onClick={this.onTrigger}
        disabled={this.props.disabled}
        className={classList.join(' ')}
      >
        <PlusOutlined />
        <span className={styles.trigger_text}>
          点击上传
        </span>
      </button>
    );
  };

  render() {
    const { uploads } = this.state;
    return (
      <div className={[
        styles.upload_items,
        'upload_item_error'].join(' ')
      }>
        <input
          type="file"
          ref={this.inputFile}
          style={{ display: 'none' }}
          onChange={this.onFileChange}
        />
        {this.renderTriggerButton()}
        {uploads.map((item: Upload, i: number) => {
          return (
            <UploadItem
              item={item}
              dataIndex={i}
              key={item.key}
              onDelete={this.onDeleteItem}
              onSuccess={this.onUploadSuccess}
            />
          );
        })}
      </div>
    );
  }
}

export default UploadFile;
